package com.yitao.cms.service.user.cmsUser;


import com.skipper.base.bean.*;
import com.skipper.base.data.querydsl.PredicateBuilder;

import com.skipper.base.json.JSONObject;
import com.skipper.base.service.GenericEntityService;
import com.yitao.client.constant.BaseConstant;
import com.yitao.cms.constant.UserErrorEnum;
import com.yitao.cms.constant.UserSession;
import com.yitao.cms.dto.operationUser.OperationPermissionDto;
import com.yitao.cms.dto.operationUser.OperationUserCmsDto;
import com.yitao.cms.enums.UserStateEnums;
import com.yitao.cms.model.operationUser.*;
import com.yitao.cms.service.sms.SmsMessagesService;
import com.yitao.cms.service.user.rollinUser.BuyerUserService;
import com.yitao.cms.utils.BaseUtils;
import com.yitao.cms.utils.MD5EncryptionUtils;
import com.yitao.cms.utils.RedisUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.EntityManager;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service
public class OperationUserService extends GenericEntityService<OperationUserCmsModel, OperationUserCmsDto, QOperationUserCmsModel> {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Value("${default_roleId}")
    private Long defaultRoleId;
    @Value("${buyer_roleId}")
    private Long buyerRoleId;
    private BaseUtils base = BaseUtils.getInstance();
    @Autowired
    private OperationUserRoleService userRoleService;
    @Autowired
    private OperationRoleService roleService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    SmsMessagesService smsMessagesService;
    @Autowired
    private OperationPermissionService permissionService;
    @Autowired
    private BuyerUserService buyerUserService;

    @Autowired
    private HttpServletRequest request;

    public OperationUserService(EntityManager entityManager) {
        super(entityManager);
    }

    protected static final String VERIFY_CODE = "VERIFY_CODE";

    /**
     * 用户添加
     *
     * @param
     * @return
     */
    @Transactional
    public DataOutput updateUser(OperationUserCmsDto userDto, HttpServletRequest request) {

        try {
            if (userDto != null && userDto.getPhone() != null) {
                if (userDto.getId() == null || userDto.getId() == 0L) {
                    //判断手机号码是否重复
                    OperationUserCmsModel userModel1 = repository.findOne(Q.phone.eq(userDto.getPhone()));
                    if (userModel1 != null) {
                        return new DataOutput(CommonStatus.BAD_REQUEST.getCode(), "手机号码已存在!");
                    }
                    userDto.setState(true);
                    userDto.setIsDelete(false);
                    userDto.setCreateBy(UserSession.getUserIdBySession(request));
                    userDto.setCreateTime(base.getNow());
                    //密码加密
                    if (!StringUtils.isEmpty(userDto.getPassword())) {
                        userDto.setPassword(MD5EncryptionUtils.getMd5(userDto.getPassword()));
                    } else {//默认密码
                        userDto.setPassword(MD5EncryptionUtils.getMd5("123456"));
                    }
                } else {
                    OperationUserCmsModel userModel = queryFactory.select(Q).from(Q).where(Q.id.eq(userDto.getId())).fetchOne();
                    if (userModel != null) {
                        userDto.setShopId(userModel.getShopId());
                        if(!StringUtils.isEmpty(userDto.getPassword())){
                            userDto.setPassword(MD5EncryptionUtils.getMd5(userDto.getPassword()));
                        }else{
                            userDto.setPassword(userModel.getPassword());
                        }
                        userDto.setState(userModel.getState());
                        userDto.setIsDelete(userModel.getIsDelete());
                        userDto.setCreateBy(userModel.getCreateBy());
                        userDto.setCreateTime(userModel.getCreateTime());
                        userDto.setLastUpdateBy(UserSession.getUserIdBySession(request));
                        userDto.setLastUpdateTime(base.getNow());
                    } else {
                        return new DataOutput(CommonStatus.BAD_REQUEST.getCode(), "用户ID有误，未查到相关数据!");
                    }
                }

                OperationUserCmsModel u = repository.save(convertDtoToEntity(userDto));
                if (u != null && userDto.getRoleId() != null) {
                   /* if (userDto.getRoleId().equals(buyerRoleId)){
                        BuyerUserModel buyerUserModel = new BuyerUserModel();
                        buyerUserModel.setOperationUserId(u.getId());
                        buyerUserModel.setShopId(u.getShopId());
                        buyerUserModel.setPhone(u.getPhone());
                        buyerUserModel.setRemarks(u.getRemarks());
                        buyerUserModel.setAvatarPath(u.getAvatarPath());
                        buyerUserModel.setUserName(u.getUserName());
                        BuyerUserModel buyerUserModel1 = buyerUserService.insertBuyerUserInfo(buyerUserModel);
                    }*/
                    OperationUserRoleModel userRoleModel = userRoleService.updateUserRole(u.getId(), userDto.getRoleId());
                    if (userRoleModel != null) {
                        return new DataOutput(u);
                    } else {
                        return new DataOutput(CommonStatus.SERVER_ERROR.getCode(), "关联角色时失败!");
                    }
                }
                return new DataOutput(CommonStatus.SERVER_ERROR);
            }
            return new DataOutput(CommonStatus.BAD_REQUEST.getCode(), "手机号码不能为空!");

        } catch (Exception e) {
            e.printStackTrace();
            logger.info("用户添加执行异常{}" + e.getMessage());
            return new DataOutput<>(CommonStatus.BAD_REQUEST.getCode(), CommonStatus.SERVER_ERROR.getMessage());

        }

    }

    /**
     * 用户注册
     *
     * @param phone
     * @param password
     * @param request
     * @return
     */
    @Transactional
    public DataOutput register(String phone, String password, HttpServletRequest request) {
        if (password != null && phone != null) {
            //判断手机号码是否重复
            OperationUserCmsModel userModel1 = repository.findOne(Q.phone.eq(phone));
            if (userModel1 != null) {
                return new DataOutput(CommonStatus.BAD_REQUEST.getCode(), "手机号码已存在!");
            }
            OperationUserCmsModel userModel = new OperationUserCmsModel();
            try {
                userModel.setPassword(MD5EncryptionUtils.getMd5(password));
            } catch (Exception e) {
                logger.info("密码加密失败{}", e.getMessage());
            }
            userModel.setUserName(phone);
            userModel.setPhone(phone);
            userModel.setState(true);
            userModel.setIsDelete(false);
            userModel.setCreateBy(UserSession.getUserIdBySession(request));
            userModel.setCreateTime(base.getNow());
            OperationUserCmsModel u = repository.save(userModel);
            if (u != null && u.getId() != null) {
                OperationUserRoleModel userRoleModel = userRoleService.updateUserRole(u.getId(), defaultRoleId);
                if (userRoleModel != null) {
                    return new DataOutput(u);
                } else {
                    return new DataOutput(CommonStatus.SERVER_ERROR.getCode(), "关联角色时失败!");
                }
            }
        }
        return new DataOutput(CommonStatus.BAD_REQUEST);

    }

    /**
     * 修改用户密码
     *
     * @param phone
     * @param password
     * @param request
     * @return
     */
    @Transactional
    public DataOutput updatePassword(String phone, String password, HttpServletRequest request) {
        if (phone != null && password != null) {
            OperationUserCmsModel userModel = queryFactory.select(Q).from(Q).where(Q.phone.eq(phone)).fetchFirst();
            if (userModel != null) {
                try {
                    String nowPassword = MD5EncryptionUtils.getMd5(password);
                    int result = repository.updateByWhere(Q.phone.eq(phone), it ->
                            it.set(Q.password, nowPassword)
                                    .set(Q.lastUpdateBy, UserSession.getUserIdBySession(request))
                                    .set(Q.lastUpdateTime, base.getNow()));
                    if (result > 0) {
                        return new DataOutput(CommonStatus.SUCCESS);
                    } else {
                        return new DataOutput(CommonStatus.SERVER_ERROR);
                    }
                } catch (Exception e) {
                    logger.info("密码加密失败{}", e.getMessage());
                    return new DataOutput(CommonStatus.SERVER_ERROR);
                }
            } else {
                return new DataOutput(CommonStatus.BAD_REQUEST.getCode(), "未找到该用户!");
            }
        }
        return new DataOutput(CommonStatus.BAD_REQUEST);

    }

    /**
     * 根据用户id查询用户信息
     *
     * @param userId
     * @return
     */
    public OperationUserCmsModel findUserInfoById(Long userId) {
        if (userId != null) {
            return queryFactory.select(Q).from(Q).where(Q.id.eq(userId)).fetchFirst();
        }
        return null;
    }


    /**
     * 用户详情
     *
     * @param userId
     * @return
     */
    public DataOutput getDetails(Long userId) {
        logger.info("查询用户入参{}：" + userId);
        OperationUserCmsModel user = queryFactory.select(Q).from(Q).where(Q.id.eq(userId)).fetchOne();
        if (user == null) {
            return new DataOutput(UserErrorEnum.USER_NULL.getCode(), UserErrorEnum.USER_NULL.getDesc());
        } else {
            OperationUserCmsDto userDto = convertEntityToDto(user);
            OperationRoleModel operationRoleModel = roleService.getRoleByUserId(user.getId());
            if (operationRoleModel != null) {
                userDto.setRoleId(operationRoleModel.getId());
                userDto.setRoleName(operationRoleModel.getRoleName());
            }
            return new DataOutput(userDto);
        }
    }

    /**
     * 用户登录
     *
     * @param phone
     * @param password
     * @param request
     * @return
     */
    public DataOutput userLogin(String phone, String password, HttpServletRequest request) {
        logger.info("用户登录，userName={}", phone);
        OperationUserCmsModel user = repository.findOne(Q.phone.eq(phone).and(Q.state.eq(true)));
        if (user == null) {
            return new DataOutput(UserErrorEnum.USER_NULL.getCode(), UserErrorEnum.USER_NULL.getDesc());
        }
        try {
            password = MD5EncryptionUtils.getMd5(password);
        } catch (Exception e) {
            return new DataOutput(UserErrorEnum.PASSWORD_ENCRYPT_EORR.getCode(), UserErrorEnum.PASSWORD_ENCRYPT_EORR.getDesc());
        }
        if (!password.equals(user.getPassword())) {
            return new DataOutput(UserErrorEnum.USERS_PASSWORD_EROOR.getCode(), UserErrorEnum.USERS_PASSWORD_EROOR.getDesc());
        }
        HttpSession session = request.getSession();
        session.setMaxInactiveInterval(360 * 60);
        session.setAttribute(UserSession.SESSION_OPERATION_USER, user);
        JSONObject jsonObject = new JSONObject();
        JSONObject permission = getMenuByUserId(user.getId());
        jsonObject.put("permissions", permission.get("permissions"));
        jsonObject.put("user", convertEntityToDto(user));
        jsonObject.put("sessionId", session.getId());
        jsonObject.put("perms", permission.get("perms"));
        logger.info("用户登录执行 出参{}" + jsonObject.toJSONString());
        return new DataOutput<>(jsonObject);
    }

    /**
     * 获取验证码
     *
     * @param phone
     * @param request
     * @return
     */
    public DataOutput getVerifyCode(String phone, HttpServletRequest request) {

        if (base.parametersIsBlank(phone)) {
            return new DataOutput<>(CommonStatus.BAD_REQUEST);
        }
        Map<String, String> map = new HashMap<>();
        try {
            //发送短信
            DataOutput dataOutput = smsMessagesService.getCode(request, phone);
            //TODO 开发环境 当前暂不触发发短信
            //DataOutput dataOutput = new DataOutput();
            //dataOutput.setStatus(CommonStatus.SUCCESS.getCode());
           // dataOutput.setData(1234);
            if (dataOutput.getStatus().equals(CommonStatus.SUCCESS.getCode())) {
                String verifyCode = String.valueOf(dataOutput.getData());
                if (org.apache.commons.lang.StringUtils.isNotBlank(verifyCode)) {
                    HttpSession session = request.getSession();
                    session.setAttribute(groupVerifyCodeByPhone(VERIFY_CODE, phone), verifyCode);
                    session.setMaxInactiveInterval(BaseConstant.SESSION_MAX_TIME);
                    map.put(VERIFY_CODE, verifyCode);
                    logger.info("用户获取验证码 手机号：{},Session key:{},Session中验证码的值：{}," +
                                    "sessionId:{}",
                            phone, groupVerifyCodeByPhone(VERIFY_CODE, phone),
                            String.valueOf(base.getFromSession(groupVerifyCodeByPhone(VERIFY_CODE, phone), request)
                            ), request.getSession().getId());
                } else {
                    return groupDataOutputByUserErrorEnum(UserErrorEnum.VERIFY_CODE_ERROR);
                }
            } else {
                return new DataOutput(UserErrorEnum.VERIFY_CODE_ERROR.getCode(), dataOutput.getMessage());
            }

        } catch (Exception e) {
            logger.error("获取验证码出现异常 手机号：{}，登录出现异常：{}", phone, e.getMessage());
            return base.getErrorMsg();
        }
        return new DataOutput(/*map*/);
    }

    /**
     * 判断验证码是否是正确
     *
     * @param phone
     * @param verifyCode
     * @param request
     * @return
     */
    public DataOutput checkoutVerifyCode(String phone, String verifyCode, HttpServletRequest request) {
        Object key = base.getFromSession(groupVerifyCodeByPhone(VERIFY_CODE, phone), request);


        //判断验证码与缓存中的验证码 是否一致
        logger.info("判断session中验证码是否一致：key:{},verifyCode:{}", key, verifyCode);

        if (key == null) {
            return groupDataOutputByUserErrorEnum(UserErrorEnum.VERIFY_NOT_FOND);
        }
        if (String.valueOf(key).equals(verifyCode)) {
            return base.getSuccessMsg();
        } else {
            return groupDataOutputByUserErrorEnum(UserErrorEnum.VERIFY_CODE_ERROR);
        }
    }


    /**
     * 用户禁用操作
     *
     * @param userId
     * @return
     */
    @Transactional
    public DataOutput updateStateById(Long userId, Boolean state, HttpServletRequest request) {
        logger.info("{}用户禁用入参" + userId);
        try {
            OperationUserCmsModel user = queryFactory.select(Q).from(Q).where(Q.id.eq(userId)).fetchOne();
            if (user == null) {
                return new DataOutput(UserErrorEnum.USER_NULL.getCode(), UserErrorEnum.USER_NULL.getDesc());
            }
            int result = repository.updateByWhere(Q.id.eq(userId),
                    it -> it.set(Q.state, state)
                            .set(Q.lastUpdateBy, UserSession.getUserIdBySession(request))
                            .set(Q.lastUpdateTime, base.getNow()));
            if (result > 0) {
                return new DataOutput(CommonStatus.SUCCESS);
            } else {
                return new DataOutput(CommonStatus.SERVER_ERROR);
            }
        } catch (Exception e) {
            logger.info("用户禁用执行异常{}", e.getMessage());
            return new DataOutput(CommonStatus.BAD_REQUEST.getCode(), e.getMessage());
        }
    }


    /**
     * 查询用户资源
     *
     * @param userId
     * @return
     */
    public JSONObject getMenuByUserId(Long userId) {
        logger.info("[{}]查询用户资源" + userId);
        QOperationRoleModel qRole = QOperationRoleModel.operationRoleModel;
        QOperationUserRoleModel qUserRole = QOperationUserRoleModel.operationUserRoleModel;
        QOperationRolePermissionModel qRolePermission = QOperationRolePermissionModel.operationRolePermissionModel;
        QOperationPermissionModel qPermission = QOperationPermissionModel.operationPermissionModel;
        // 查询用户的资源
        List<OperationPermissionModel> permissions = queryFactory.select(qPermission).distinct().from(Q).innerJoin(qUserRole).where(Q.id.eq(userId)).on(Q.id.eq(qUserRole.userId)).innerJoin(qRole)
                .on(qUserRole.roleId.eq(qRole.id)).innerJoin(qRolePermission).on(qRole.id.eq(qRolePermission.roleId)).innerJoin(qPermission).on(qRolePermission.permissionId.eq(qPermission.id))
                .where(qPermission.state.eq(1)).fetch();

        // 权限
        List<String> perms = new ArrayList<>();
        List<String> permlis = new ArrayList<>();
        List<String> buttonList = new ArrayList<>();
        for (OperationPermissionModel permission : permissions) {
            if (permission.getResourceType() == 0) {//0菜单，1按钮
                perms.add(String.valueOf(permission.getId()));
            } else {
                buttonList.add(permission.getPerms());
            }
            permlis.add(permission.getPerms());
        }
        // 把权限存到redis中
        setPerms2Redis(String.valueOf(userId), perms);
        List<OperationPermissionModel> permissionByParentList = permissionService.getListByParentId(0L, perms, UserStateEnums.UserStateEnum.ENABLE.getCode());
        // 查询根菜单的列表
      /*  List<OperationPermissionModel> permissions2 = queryFactory.select(qPermission).distinct().from(Q).innerJoin(qUserRole).where(Q.id.eq(userId)).on(Q.id.eq(qUserRole.userId)).innerJoin(qRole)
                .on(qUserRole.roleId.eq(qRole.id)).innerJoin(qRolePermission).on(qRole.id.eq(qRolePermission.roleId)).innerJoin(qPermission).on(qRolePermission.permissionId.eq(qPermission.id))
                .where(qPermission.state.eq(1).and(qPermission.parentId.eq(0L))).fetch();*/
        // 递归获取子菜单
        List<OperationPermissionDto> permissionDtos = permissionService.getPermissionTreeList(permissionByParentList, perms, UserStateEnums.UserStateEnum.ENABLE.getCode());
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("permissions", permissionDtos);
        jsonObject.put("perms", buttonList);
        return jsonObject;

    }

    /**
     * 用户列表
     *
     * @return
     */
    public PagedOutput<OperationUserCmsDto> userList(String userName, String phone, Long roleId, Integer pageNo, Integer pageSize) {
        PagedInput pagedInput = new PagedInput(pageSize, pageNo);
        QOperationRoleModel qOperationRoleModel = QOperationRoleModel.operationRoleModel;
        QOperationUserRoleModel qOperationUserRoleModel = QOperationUserRoleModel.operationUserRoleModel;
        List<OperationUserCmsModel> userModelList = queryFactory.select(Q).from(Q).
                leftJoin(qOperationUserRoleModel).on(Q.id.eq(qOperationUserRoleModel.userId))
                .leftJoin(qOperationRoleModel).on(qOperationUserRoleModel.roleId.eq(qOperationRoleModel.id))
                .where(PredicateBuilder.conjunction()
                        .ifHasTextThenAnd(userName, () -> Q.userName.eq(userName))
                        .ifHasTextThenAnd(phone, () -> Q.phone.eq(phone))
                        .ifNotNullThenAnd(roleId, () -> qOperationRoleModel.id.eq(roleId))
                        .and(() -> Q.isDelete.eq(false)).get())
                .offset((pageNo - 1) * pageSize).limit(pageSize).orderBy(Q.createTime.desc()).fetch();

        Long listSize = queryFactory.select(Q).from(Q).
                leftJoin(qOperationUserRoleModel).on(Q.id.eq(qOperationUserRoleModel.userId))
                .leftJoin(qOperationRoleModel).on(qOperationUserRoleModel.roleId.eq(qOperationRoleModel.id))
                .where(PredicateBuilder.conjunction()
                        .ifHasTextThenAnd(userName, () -> Q.userName.eq(userName))
                        .ifHasTextThenAnd(phone, () -> Q.phone.eq(phone))
                        .ifNotNullThenAnd(roleId, () -> qOperationRoleModel.id.eq(roleId))
                        .and(() -> Q.isDelete.eq(false)).get()).fetchCount();

        List<OperationUserCmsDto> userDtoList = userModelList.stream().map(it -> {
            OperationUserCmsDto operationUserCmsDto = convertEntityToDto(it);
            OperationRoleModel roleModel = roleService.getRoleByUserId(it.getId());
            if (null != roleModel) {
                operationUserCmsDto.setRoleId(roleModel.getId());
                operationUserCmsDto.setRoleName(roleModel.getRoleName());
            }
            return operationUserCmsDto;
        }).collect(Collectors.toList());
        return new PagedOutput(pagedInput, listSize, userDtoList);
    }


    /**
     * 把用户权限存到redis中
     *
     * @param userId
     * @param perms
     */
    public void setPerms2Redis(String userId, List<String> perms) {
        if (redisUtil.idNull(userId)) {
            redisUtil.delObject(userId);
        }
        redisUtil.setObejct(userId, perms);

    }


    /**
     * 用户退出
     *
     * @return
     */
    public DataOutput loginOut(HttpServletRequest request) {
        try {
            HttpSession session = request.getSession();
            session.removeAttribute(UserSession.SESSION_OPERATION_USER);
            return new DataOutput(CommonStatus.SUCCESS);
        } catch (Exception e) {
            logger.info("用户退出执行错误{}" + e.getMessage());
            return new DataOutput(CommonStatus.SERVER_ERROR);
        }
    }

    private String groupVerifyCodeByPhone(String verifyCode, String phone) {
        return verifyCode + "_" + phone;
    }

    private DataOutput groupDataOutputByUserErrorEnum(UserErrorEnum userErrorEnum) {
        return new DataOutput(userErrorEnum.getCode(), userErrorEnum.getDesc());

    }

    @Transactional
    public void updateUser(OperationUserCmsModel operationUserCmsModel) {
        OperationUserCmsModel operationUserCmsModel1 = queryFactory.select(Q).from(Q).where(Q.id.eq(operationUserCmsModel.getId())).fetchOne();
        if (operationUserCmsModel1 != null) {
            operationUserCmsModel1.setShopId(operationUserCmsModel.getShopId());
            operationUserCmsModel1.setLastUpdateTime(operationUserCmsModel.getLastUpdateTime());
            operationUserCmsModel1.setLastUpdateBy(operationUserCmsModel.getId());
        }
        HttpSession session = request.getSession();
        session.setMaxInactiveInterval(360 * 60);
        session.setAttribute(UserSession.SESSION_OPERATION_USER, operationUserCmsModel1);
    }
}
